
#include "stdafx.h"
#include <iostream>
#include <string>
#include "BmpCaptor.h"

#include "mmsystem.h"
#pragma comment(lib,"winmm.lib")

#define R_COLOR 0
#define G_COLOR 1
#define B_COLOR 2

using namespace std;

//construct functions
BmpCaptor::BmpCaptor():
m_iImageWidth(0), m_iImageHeight(0), m_iBitsPerPixel(0), m_iImageDataSize(0), m_pImageData(NULL), m_timerId(-1),toScale(true)
{
	m_pVCam = NULL;
	::CoInitialize(NULL);
	HRESULT hr = CoCreateInstance(CLSID_VCamSDK, NULL, CLSCTX_INPROC, IID_IVCamSDK, 
		reinterpret_cast<void**>(&m_pVCam));

	m_pLSCap = new LScreenCap();
	m_pLSCap->MirrorDriverStart();
}
/*
BmpCaptor::BmpCaptor(int width, int height, int bitsPerPixel, unsigned char* imageData):
m_iImageWidth(width), m_iImageHeight(height), m_iBitsPerPixel(bitsPerPixel)
{
	int iLineByteCnt = getRealWidth();
    m_iImageDataSize = iLineByteCnt * m_iImageHeight;

	m_pImageData = new unsigned char[m_iImageDataSize];
	for(int i=0;i<m_iImageDataSize;i++)
		m_pImageData[i] = imageData[i];

	m_pVCam = NULL;
	::CoInitialize(NULL);
	HRESULT hr = CoCreateInstance(CLSID_VCamSDK, NULL, CLSCTX_INPROC, IID_IVCamSDK, 
		reinterpret_cast<void**>(&m_pVCam));

	m_pLSCap = new LScreenCap();
	m_pLSCap->MirrorDriverStart();
}

BmpCaptor::BmpCaptor(string filePath)
{
	readBmp("d:\\1.bmp");

	//initial m_pVCam
	m_pVCam = NULL;
	::CoInitialize(NULL);
	HRESULT hr = CoCreateInstance(CLSID_VCamSDK, NULL, CLSCTX_INPROC, IID_IVCamSDK, 
		reinterpret_cast<void**>(&m_pVCam));
}*/

//deconstruction function
BmpCaptor::~BmpCaptor()
{
    if(m_pImageData != NULL)
		delete []m_pImageData;

	m_pLSCap->MirrorDriverStop();
	delete []m_pLSCap;		 
	
	delete []m_pVCam;
	::CoUninitialize();
}

//get data functions
unsigned char* BmpCaptor::getImageData()
{
	return m_pImageData;
}

int BmpCaptor::getImageDataSize()
{
	return m_iImageDataSize;
}

int BmpCaptor::getImageHeight()
{
	return m_iImageHeight;
}

int BmpCaptor::getImageWidth()
{
	return m_iImageWidth;
}

int BmpCaptor::getBitsPerPixel()
{
	return m_iBitsPerPixel;
}

int BmpCaptor::getRealWidth()
{
	return (m_iImageWidth * m_iBitsPerPixel/8 +3)/4*4;
}

//set data functions
void BmpCaptor::setImageSize(int width,int height)
{
	m_iImageWidth = width;
	m_iImageHeight = height;
}

void BmpCaptor::setImage(int width, int height, int bitsPerPixel, unsigned char* data)
{
	m_iImageWidth = width;
	m_iImageHeight = height;
	m_iBitsPerPixel = bitsPerPixel;
	m_iImageDataSize = getRealWidth() * m_iImageHeight;

    if(m_pImageData != NULL)
		delete []m_pImageData;

	m_pImageData = new unsigned char[m_iImageDataSize];
	for(int i=0;i<m_iImageDataSize;i++)
		m_pImageData[i] = data[i];
}

//output image data
void BmpCaptor::outputImage()
{
	m_pVCam->PlayBuffer(m_pImageData, m_iImageWidth, m_iImageHeight);
}

//get the image data and output
void BmpCaptor::captureImage()
{
	//do get image data from m_pLSCap
	char* imageData = m_pLSCap->GetScreenData();

	//get monitor width and height
	int width = GetSystemMetrics(SM_CXSCREEN);       
    int height = GetSystemMetrics(SM_CYSCREEN); 

	unsigned char* newImageData = new unsigned char[width*height*3];

    //get distinguishability of screen
    DEVMODE dm;
	dm.dmSize=sizeof(DEVMODE);    
    EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&dm);


	//judge the bits per pixel and change to 24
	if(dm.dmBitsPerPel == 16)
	{
		int lineBytes = 2 * width;

		//5-6-5 format as r-g-b
        WORD* wByte;

		for(int i=0;i < height;i++)
		{
			for(int j=0;j < width;j++)
			{
				wByte = (WORD*)(imageData + i * lineBytes + j * 2);
				unsigned char b = (*wByte & 0xF800) >> 8;
				unsigned char g = (*wByte & 0x07E0) >> 3;
				unsigned char r = (*wByte & 0x001F) << 3;

				newImageData[ (height-1-i) * 3 * width + j*3 + 0] = r;
				newImageData[ (height-1-i) * 3 * width + j*3 + 1] = g;
				newImageData[ (height-1-i) * 3 * width + j*3 + 2] = b;
			}
		}
		
	}

	else if(dm.dmBitsPerPel == 32)
	{
		int lineBytes = 4 * width;
		for(int i=0;i < height;i++)
		{
			for(int j=0;j < width;j++)
			{				
				newImageData[(height-1-i) * 3 * width + j*3 + 0] = (unsigned char)(imageData[i * lineBytes + j*4 + 0]);
				newImageData[(height-1-i) * 3 * width + j*3 + 1] = (unsigned char)(imageData[i * lineBytes + j*4 + 1]);
				newImageData[(height-1-i) * 3 * width + j*3 + 2] = (unsigned char)(imageData[i * lineBytes + j*4 + 2]);
			}
		}
	}

	else
	{
		cout << "the bits per pixel is " << dm.dmBitsPerPel << endl;
		return;
	}

	/*
	if(toScale){

	//scale the image (or change the resolution of the image)	
	unsigned char* newImage = new unsigned char[m_iImageWidth * m_iImageHeight * 3];

	double ky = (double)m_iImageWidth/(double)width;
	double kx = (double)m_iImageHeight/(double)height;

	for(int i=0; i < m_iImageHeight; i++)
	{
		double u = i/kx;
		int iu = u;
		double a = u-iu;

		int iX1 = i * 3 * m_iImageWidth;

		for(int j=0; j < m_iImageWidth; j++)
		{
			double v = j/ky;
			int iv = v;			
			double b = v-iv;

			int iX2 = iX1 + j*3;

			newImage[iX2 + R_COLOR] = biInterpolation(a,b,iu,iv,newImageData,R_COLOR,width);
			newImage[iX2 + G_COLOR] = biInterpolation(a,b,iu,iv,newImageData,G_COLOR,width);
			newImage[iX2 + B_COLOR] = biInterpolation(a,b,iu,iv,newImageData,B_COLOR,width);

			//convert pixel
            //newImage[iX2 + 0] = newImageData[iU2 + 0];//r
			//newImage[iX2 + 1] = newImageData[iU2 + 1];//g
			//newImage[iX2 + 2] = newImageData[iU2 + 2];//b
		}
	}

	//output
	//m_pVCam->PlayBuffer(newImageData, width, height);
	m_pVCam->PlayBuffer(newImage, m_iImageWidth, m_iImageHeight);
	delete []newImageData;
	delete []newImage;
	}
	else{*/
		m_pVCam->PlayBuffer(newImageData, width, height);
		delete []newImageData;
	//}
}

//scale image
unsigned char BmpCaptor::biInterpolation(double a, double b, int u, int v, unsigned char* imageData, int rgbType,int width)
{
	unsigned char newImagePixel;
    double t1 = a * imageData[(u + 1) * 3 * width + 3 * v + rgbType] + (1-a) * imageData[(u + 1) * 3 * width + 3 * ( v + 1) + rgbType];
	double t2 = a * imageData[u * 3 * width + 3 * (v+1) + rgbType] + (1-a) * imageData[u * 3 * width + 3 * v + rgbType];
	newImagePixel = b*t1+(1-b)*t2+0.5;

	if(newImagePixel>255)
		newImagePixel = 255;

	return newImagePixel;
}

//set if scale
void BmpCaptor::setToScale(bool flag)
{
	toScale = flag;
}

//read bitmap file
bool BmpCaptor::readBmp(char *bmpName)
{
	FILE *fp = fopen(bmpName, "rb");
	if(fp == 0)
		return false;

	fseek(fp, sizeof(BITMAPFILEHEADER), 0);

    BITMAPINFOHEADER head;
	fread(&head, sizeof(BITMAPINFOHEADER), 1, fp);

	m_iImageWidth = head.biWidth;
	m_iImageHeight = head.biHeight;
	m_iBitsPerPixel = head.biBitCount;

	int lineByte = getRealWidth();

	m_pImageData = new unsigned char[lineByte * m_iImageHeight];
	fread(m_pImageData, 1, lineByte * m_iImageHeight, fp);

	fclose(fp);

	return true;
}

//call back function 
//get mirror driver's screen image data and 
//call captureImage function
void WINAPI display(UINT wTimerID, UINT msg, 
					DWORD dwUser,DWORD dw1,DWORD dw2) 
{ 
	BmpCaptor *cap = (BmpCaptor *)dwUser;

	//call BmpCaptor's captureImage function using dwUser	
	cap->captureImage();
} 

//periodically call display function
UINT BmpCaptor::startPerCap(int fps)
{	
	UINT interval;	
    interval = 1000/fps;	
	m_timerId = timeSetEvent(interval, 0, display,( DWORD )this, TIME_PERIODIC);
	return m_timerId;
}

void BmpCaptor::stopPerCap()
{
	if(m_timerId != -1 || m_timerId != 0)
	{
		timeKillEvent(m_timerId); 
		m_timerId = -1;
	}
}
/*
int main()
{
	BmpCaptor bc("d:\\1.bmp");
	bc.outputImage();
	return 1;
}
*/